#pragma once

using namespace System;
using namespace NUnit::Framework;
using namespace LatoolNet;

namespace LatoolNetTest {

	[TestFixture]
	public ref class DoubleGeneralBandMatrixTest {
	public:
		[Test]
		void TestSetGetValue() {

			int rownum = 10;
			int colnum = 10;
			int kl = 2;
			int ku = 2;
			Matrix ^ expected = gcnew Matrix(rownum, colnum);
			Matrix ^ actual = gcnew Matrix(rownum, colnum, kl, ku);

			Assert::AreEqual(MatrixType::DoubleGeneralBand, actual->Type, "Test: Type");

			Random ^ randgen = gcnew Random();

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						expected[i, j] = d;
						actual[i, j] = d;
					} else {
						expected[i, j] = 0.0;
						actual[i, j] = 0.0;
					}
				}
			}

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(expected[i, j], actual[i, j], 1e-10, "Test: Set/Get");	
				}
			}

		};

		[Test]
		void TestSolve() {

			int rownum = 10;
			int colnum = 10;
			int kl = 2;
			int ku = 2;
			Matrix ^ bandmat = gcnew Matrix(rownum, colnum, kl, ku);

			Random ^ randgen = gcnew Random();

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						bandmat[i, j] = d;
					} else {
						bandmat[i, j] = 0.0;
					}
				}
			}

			Matrix ^ expected = gcnew Matrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				expected[i, 0] = randgen->NextDouble() * 10 - 5;	
			}

			Matrix ^ b = bandmat * expected;

			//LUFactorization::Solve(bandmat, b);
			LinearEquation::Solve(bandmat, b);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0], b[i, 0], 1e-10, "Test: Solve.");
			}

		};

		[Test]
		void TestFactorizedSolve() {

			int rownum = 10;
			int colnum = 10;
			int kl = 3;
			int ku = 3;

			Matrix ^ bandmat = gcnew Matrix(rownum, colnum, kl, ku);
			Random ^ randgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						bandmat[i, j] = d;
					} else {
						bandmat[i, j] = 0.0;
					}
				}
			}

			Matrix ^ expected = gcnew Matrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				expected[i, 0] = randgen->NextDouble() * 10 - 5;	
			}

			Matrix ^ b = bandmat * expected;

			//LUFactorization::Factorize(bandmat);
			LinearEquation::Factorize(bandmat);

			//LUFactorization::Solve(bandmat, b);
			LinearEquation::Solve(bandmat, b);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0], b[i, 0], 1e-10, "Test: Factorized Solve.");
			}

		};

		[Test]
		void TestRepeatedFactorizedSolve() {

			int rownum = 10;
			int colnum = 10;
			int kl = 3;
			int ku = 3;

			Matrix ^ bandmat = gcnew Matrix(rownum, colnum, kl, ku);
			Random ^ randgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						bandmat[i, j] = d;
					} else {
						bandmat[i, j] = 0.0;
					}
				}
			}

			Matrix ^ expected = gcnew Matrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				expected[i, 0] = randgen->NextDouble() * 10 - 5;	
			}

			Matrix ^ b = bandmat * expected;


			Matrix ^ expected2 = gcnew Matrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				expected2[i, 0] = randgen->NextDouble() * 10 - 5;	
			}

			Matrix ^ b2 = bandmat * expected2;

			//LUFactorization::Factorize(bandmat);
			LinearEquation::Factorize(bandmat);

			//LUFactorization::Solve(bandmat, b);
			LinearEquation::Solve(bandmat, b);

			//LUFactorization::Solve(bandmat, b2);
			LinearEquation::Solve(bandmat, b2);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0], b[i, 0], 1e-10, "Test: Repeated Factorized Solve.");
			}

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected2[i, 0], b2[i, 0], 1e-10, "Test: Repeated Factorized Solve.");
			}

		};

		[Test]
		void TestRepeatedSolve() {

			int rownum = 10;
			int colnum = 10;
			int kl = 3;
			int ku = 3;

			Matrix ^ bandmat = gcnew Matrix(rownum, colnum, kl, ku);
			Random ^ randgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						bandmat[i, j] = d;
					} else {
						bandmat[i, j] = 0.0;
					}
				}
			}

			Matrix ^ expected = gcnew Matrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				expected[i, 0] = randgen->NextDouble() * 10 - 5;	
			}

			Matrix ^ b = bandmat * expected;


			Matrix ^ expected2 = gcnew Matrix(rownum, 1);

			for (int i = 0; i < rownum; i++) {
				expected2[i, 0] = randgen->NextDouble() * 10 - 5;	
			}

			Matrix ^ b2 = bandmat * expected2;

			//LUFactorization::Solve(bandmat, b);
			LinearEquation::Solve(bandmat, b);

			//LUFactorization::Solve(bandmat, b2);
			LinearEquation::Solve(bandmat, b2);

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected[i, 0], b[i, 0], 1e-10, "Test: Repeated Factorized Solve.");
			}

			for (int i = 0; i < rownum; i++) {
				Assert::AreEqual(expected2[i, 0], b2[i, 0], 1e-10, "Test: Repeated Factorized Solve.");
			}

		};

		[Test]
		void TestClone() {

			int rownum = 10;
			int colnum = 10;

			int kl = 3;
			int ku = 3;
			Matrix ^ bandmat = gcnew Matrix(rownum, colnum, kl, ku);
			Matrix ^ expected = gcnew Matrix(rownum, colnum);

			Random ^ randgen = gcnew Random();
			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						bandmat[i, j] = d;
						expected[i, j] = d;
					} else {
						bandmat[i, j] = 0.0;
						expected[i, j] = 0.0;
					}
				}
			}

			Matrix ^ bandmatclone = bandmat->Clone();

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					if ((i == j) || ((j > i) && (j - i <= ku)) || ((i > j) && (i - j <= kl))) {
						double d = randgen->NextDouble() * 10;
						bandmat[i, j] = d;
					} else {
						bandmat[i, j] = 0.0;
					}
				}
			}

			for (int i = 0; i < rownum; i++) {
				for (int j = 0; j < colnum; j++) {
					Assert::AreEqual(expected[i, j], bandmatclone[i, j], 1e-20, "Test: Clone");
				}
			}

			Assert::AreEqual(expected->IsFactorized, bandmatclone->IsFactorized, "Test: Clone");

			//LUFactorization::Factorize(bandmat);
			LinearEquation::Factorize(bandmat);

			bandmatclone = bandmat->Clone();

			Assert::AreEqual(bandmat->IsFactorized, bandmatclone->IsFactorized, "Test: Clone");



		};
	};

}